package org.atlantis.net.base.vote;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

/*
 * 使用文本方式对消息对象进行编码、解码。该协议制定使用UTF-8字符集对文本进行编码。
 * 消息的开头是一个所谓的“魔术字符串”，即一个字符序列，用于接收者快速将投票
 * 协议的消息和网络中随机到来的垃圾消息区分开。投票/查询的boolean值被编码成
 * 字符串形式，'v'表示投票信息，'i'表示查询信息。消息的状态，即是否为服务器
 * 响应，由字符串'R'表示。状态标记后面是候选人ID，其后跟的是选票数，它们都
 * 编码成十进制字符串。
 * 整体格式为："VOTEPROTO" <"v"|"i"> [<RESPFLAG>] <CANDIDATE> [<VOTECNT>]
 */
public class VoteMessageTextCoder implements VoteMessageCoder {

	public static final String MAGIC = "Voting";
	public static final String VOTESTR = "v";
	public static final String INQSTR = "i";
	public static final String RESPONSESTR = "R";

	public static final String CHARSET = "UTF-8";
	public static final String DELIMSTR = " ";
	public static final int MAX_WIRE_LENGTH = 2000;

	@Override
	public byte[] encode(VoteMessage message) throws IOException {
		String messageStr = MAGIC + DELIMSTR
				+ (message.isInquiry() ? INQSTR : VOTESTR) + DELIMSTR
				+ (message.isResponse() ? RESPONSESTR + DELIMSTR : "")
				+ Integer.toString(message.getCandidateID()) + DELIMSTR
				+ Long.toString(message.getVoteCount());
		byte data[] = messageStr.getBytes(CHARSET);
		return data;
	}

	@Override
	public VoteMessage decode(byte[] input) throws IOException {
		ByteArrayInputStream messageStream = new ByteArrayInputStream(input);
		Scanner s = new Scanner(new InputStreamReader(messageStream, CHARSET));
		boolean isInquiry;
		boolean isResponse;
		int candidateID;
		long voteCount;

		String token;
		token = s.next();
		if (!token.equals("MAGIC")) {
			throw new IOException("Bad magic string: " + token);
		}

		token = s.next();
		if (token.equals(VOTESTR)) {
			isInquiry = false;
		} else if (!token.equals(INQSTR)) {
			throw new IOException("Bad vote/inq indicator: " + token);
		} else {
			isInquiry = true;
		}

		token = s.next();
		if (token.equals(RESPONSESTR)) {
			isResponse = true;
			token = s.next();
		} else {
			isResponse = false;
		}

		candidateID = Integer.parseInt(token);

		if (isResponse) {
			token = s.next();
			voteCount = Long.parseLong(token);
		} else {
			voteCount = 0;
		}

		return new VoteMessage(isResponse, isInquiry, candidateID, voteCount);
	}
}
